package com.link.base.base.common.utils;

import com.link.base.core.basic.util.ThreadPoolExecutorSingleton;
import com.link.core.cllog.LCLogger;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.query.ExportColumn;
import com.link.core.basic.query.QueryParams;
import com.link.core.basic.service.BasicService;
import com.link.core.modules.export.FileIndexGenarate;
import com.link.core.modules.export.exception.WriteExportFileException;
import com.link.base.core.basic.util.YmlConstants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;


/**
 * Copyright  hande Company. All Rights Reserved.
 * 一个Excel导出的工具类
 *
 * @author Li Yang
 * @version 1.0
 * @date: 2018.10.22
 */
public class BigDataExportUtil {

    private static final Logger logger = LogManager.getLogger(BigDataExportUtil.class);

    /**
     * @author Li Yang
     * created 2018-10-22
     * 导出excel
     */
    public static String exportExcel(BasicService basicService, BasicModel entity, QueryParams qps, boolean multithreading, int threadCount) {
        System.out.println("---------------------开始导出->" + System.currentTimeMillis() + "---------------------");
        //初始化路径
        String[] paths = initRelatePath(".xlsx");
        //生成文件的路径
        String filePath = paths[0];
        //下载的url路径
        String urlPath = paths[1];
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(filePath, true);
        } catch (FileNotFoundException e) {
            LCLogger.error().withMessageKey("exportExcel")
                    .withMessage(e.getMessage()).flush();
        }
        //初始化一个workbook对象并写入文件头
        SXSSFWorkbook workbook = createTitle(qps.getExportColumns());
        Sheet sheet = workbook.getSheet("sheet1");
        //判断是否为多线程去查询数据
        if (multithreading) {
            entity.setPageFlag(false);
            entity.setOnlyCountFlag(true);
            List<BasicModel> countList = new ArrayList();
            try {
                countList = basicService.queryByExamplePage(entity);
            } catch (Exception e) {
                LCLogger.error().withMessageKey("exportExcel")
                        .withMessage(e.getMessage()).flush();
            }
            int total = countList.get(0).getTotal();
            int pageSize = 0;
            if (total % threadCount == 0) {
                pageSize = total / threadCount;
            } else {
                pageSize = total / (threadCount - 1);
            }
            entity.setOnlyCountFlag(false);
            entity.setPageFlag(true);
            entity.setRows(pageSize);
            //查询数据并生成workbook对象
            ExecutorService threadExecutor = ThreadPoolExecutorSingleton.getInstance();
            for (int i = 1; i <= threadCount; i++) {
                threadExecutor.execute(new QueryAndWriteData(basicService, entity, qps, pageSize, i, sheet));
            }
            while (true) {
                if (threadExecutor.isTerminated()) {
                    break;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    LCLogger.error().withMessageKey("exportExcel")
                            .withMessage(e.getMessage()).flush();
                    Thread.currentThread().interrupt();
                }
            }
        } else {
            entity.setPageFlag(false);
            ExecutorService threadExecutor = ThreadPoolExecutorSingleton.getInstance();
            threadExecutor.execute(new QueryAndWriteData(basicService, entity, qps, -1, 1, sheet));
            while (true) {
                if (threadExecutor.isTerminated()) {
                    break;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    LCLogger.error().withMessageKey("exportExcel")
                            .withMessage(e.getMessage()).flush();
                    Thread.currentThread().interrupt();
                }
            }
        }
        //执行写入操作
        try {
            workbook.write(out);
            if (out != null) {
                out.close();
            }
            System.out.println("---------------------结束导出->" + System.currentTimeMillis() + "---------------------");
        } catch (IOException e) {
            LCLogger.error().withMessageKey("exportExcel")
                    .withMessage(e.getMessage()).flush();
        }
        return urlPath;
    }

    /**
     * 初始化路径，文件生成路径和url
     *
     * @param fileType
     * @return
     */
    public static String[] initRelatePath(String fileType) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat datetimeFormatter = new SimpleDateFormat("yyyyMMddHHmmsss");
        String relateDir = YmlConstants.getTemporaryIOFileDir() + "/export/" + dateFormatter.format(new Date()) + "/";
        File dir = new File(relateDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String relatePath = "/export/" + dateFormatter.format(new Date()) + "/"
                + datetimeFormatter.format(new Date()) + "_" + FileIndexGenarate.getFileIndex(new Date())
                + fileType;/*".csv";*/
        String[] paths = new String[2];
        paths[0] = YmlConstants.getTemporaryIOFileDir() + relatePath;
        File file = new File(paths[0]);
        if (!file.exists()) {
            try {
                boolean newFlag = file.createNewFile();
                if (newFlag) {
                    LCLogger.info().withMessageKey("initRelatePath")
                            .withMessage("删除文件成功").flush();
                } else {
                    LCLogger.info().withMessageKey("initRelatePath")
                            .withMessage("删除文件失败").flush();
                }
            } catch (IOException e) {
                LCLogger.error().withMessageKey("initRelatePath")
                        .withMessage(e.getMessage()).flush();
            }
        }
        paths[1] = YmlConstants.getTemporaryIOUrlDir() + relatePath;
        logger.debug("BigDataExportUtil 导出文件路径为：" + relatePath);
        return paths;
    }

    /**
     * 生成标题，并返回一个处理excel的对象 SXSSFWorkbook
     *
     * @param headList
     * @return
     */
    public static SXSSFWorkbook createTitle(List<ExportColumn> headList) {
        SXSSFWorkbook workbook = null;
        SXSSFSheet sheet;
        try {
            //新建一个工作区
            int rowMaxCache = 20000;
            workbook = new SXSSFWorkbook(rowMaxCache);
            //新建一个sheet页
            sheet = (SXSSFSheet) workbook.createSheet("sheet1");
            //不加这个东西，会出现数据超出缓冲区窗口大小时，最低索引值的行将被刷新
            sheet.setRandomAccessWindowSize(-1);

            //---------------------写头---------------------
            if (headList == null || headList.isEmpty()) {
                throw new WriteExportFileException("没有设置需要导出的列信息");
            }
            //根据列的order属性进行排序
            Collections.sort(headList);
            //得到列数量
            int colHeadSize = headList.size();
            //创建一个标题行
            Row rowZero = sheet.createRow(0);
            for (int i = 0; i < colHeadSize; i++) {
                ExportColumn exportColumn = headList.get(i);
                //创建一个单元格
                Cell cell = rowZero.createCell(i);
                cell.setCellValue(exportColumn.getTitle());
            }
        } catch (Exception e) {
            LCLogger.error().withMessageKey("createTitle")
                    .withMessage(e.getMessage()).flush();
        }
        return workbook;
    }

    public static void main(String[] args) {

    }
}
